#!/usr/bin/env ruby

# Copyright (c) 2010-2012 Microsoft Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#	http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'rubygems'
require 'ruby-aws'
require 'optparse'

require './include/config'
require './include/proxy'
require './include/requester'

@config = MOS::Config.create
@mturk = Amazon::WebServices::MechanicalTurkRequester.new :Host => @config[:Server]

def forceExpireHIT(hit_id)
	if hit_id.length > 0
		begin
			printf("Expiring HIT with Id %s\n", hit_id)
			@mturk.ForceExpireHIT( :HITId => hit_id )
		rescue => e
#			omit errors, because we sometimes forceExpire an already expired HIT
#			$stderr.printf("Error expiring HIT with Id %s: %s\n", hit_id, e.message)
		end
	end
end

def disposeHIT(hit_id)
	if @options[:delete] && hit_id.length > 0
		begin
			printf("Deleting HIT with Id %s\n", hit_id)
			@mturk.DisposeHIT( :HITId => hit_id )
		rescue => e
			$stderr.printf("Error deleting HIT with Id %s: %s\n", hit_id, e.message)
		end
	end
end

def deleteHIT(hit)
	printf("Processing HIT with Id %s and Status %s\n", hit[:HITId], hit[:HITStatus])
	case hit[:HITStatus]
		when 'Assignable'
			forceExpireHIT(hit[:HITId])
			disposeHIT(hit[:HITId])

		when 'Unassignable'
			forceExpireHIT(hit[:HITId])
			printf("Unassignable HITs must be completed or returned before being deleted.\n")

		when 'Reviewable', 'Reviewing'
			forceExpireHIT(hit[:HITId])

			if hit[:NumberOfAssignmentsAvailable] == hit[:MaxAssignments]
				disposeHIT(hit[:HITId])
			else
				assignment_list = @mturk.collect_assignments_from_HITId(hit[:HITId])
				if assignment_list.detect { |a| a[:AssignmentStatus] == 'Submitted' } == nil
					disposeHIT(hit[:HITId])
				else
					printf("This HIT has unreviewed assignments, and cannot be deleted.\n");
				end
			end

		when 'Disposed'
			printf("HIT already disposed -- nothing left to do.\n")
	end
	printf("\n")
end

@options = { }
optparse = OptionParser.new do |opts|
	opts.banner = "Usage: #{$0} [options]"
 
	@options[:quiet] = false
	opts.on( '-q', '--quiet', 'Do not print any messages (implies -f)' ) do
		@options[:quiet] = true
	end

	@options[:all] = false
	opts.on( '-a', '--all', 'Operate on all HITs in the account' ) do
		@options[:all] = true
	end

	@options[:force] = false
	opts.on( '-f', '--force', 'Do not ask for confirmation' ) do
		@options[:force] = true
	end

	@options[:delete] = false
	opts.on( '-d', '--delete', 'Expire and deletes HITs (default is to only expire)' ) do
		@options[:delete] = true
	end
 
	opts.on( '-h', '--help', 'Display this screen' ) do
		puts opts
		exit
	end

	opts.on_tail("")
	opts.on_tail("This script unconditionally expires and (optionally) deletes unsubmitted and reviewed HITs.")
	opts.on_tail("It can operate on all HITs in the MTurk account, or only on HITs identified in given files.")
end

begin
	optparse.parse!
rescue OptionParser::ParseError => e
	$stderr.puts("Error parsing command-line arguments: " + e.message)
	$stderr.puts("Try '#{$0} --help' for more information.")
	exit
end

if @options[:quiet]
	@options[:force] = true
	devnull = File.exist?('/dev/null') ? '/dev/null' : 'NUL'
	$stdout = File.new(devnull, 'w')
end

if !@options[:force]
	if @options[:delete]
		printf("Are you sure you want to expire and delete all unsubmitted HITs? (y/n) ")
	else
		printf("Are you sure you want to expire all unsubmitted HITs? (y/n) ")
	end

	response = STDIN.gets.chomp.downcase
	if response != 'y'
		printf("Exiting...\n")
		exit
	end
end

if @options[:all]
	hit_list = @mturk.collect_HITs
	hit_list.each { |hit| deleteHIT(hit) }
else
	if !File.exists?(@config[:HITSuccessFile])
		$stderr.printf("There are no HITs to expire or delete. Please run CreateHITs.rb first.\n")
		$stderr.printf("Exiting...\n")
		exit
	end

	hits = Amazon::Util::DataReader.load(@config[:HITSuccessFile], :Tabular)
	hits.each_index do |i|
		hit_id = hits[i][:HITId]
		begin
			r = @mturk.GetHIT( :HITId => hit_id )
			deleteHIT(r[:HIT])
		rescue => e
			$stderr.printf("Error fetching HIT with ID %s: %s\n", hit_id, e.message)
		end
	end
end

